<?php
/**
 * Created by PhpStorm.
 * User: stupboy
 * Date: 2018/4/16
 * Time: 8:08
 * Mail:87658989@qq.com
 * 单例模式
 * 封装redis方法
 */
namespace app\base\service;
use app\base\exception\CacheException;
use think\Config;

/**
 * Class Redis 单例模式引用
 * @package app\base\service
 */
class Redis
{
    public $redis;
    public $redisConfig;
    public $appPrefix;

    public function __construct()
    {
        try{
            $this->redis         = new \Redis();
            $this->redisConfig   = Config::get('database.redis');
            $this->appPrefix     = $this->redisConfig['prefix'];
            $this->redis->connect($this->redisConfig['host'],$this->redisConfig['port']);
            !empty($this->redisConfig['password']) && $this->redis->auth($this->redisConfig['password']);
        }catch (\RedisException $e){
            // 勿删除有些版本不写着代码无法使用
            throw new CacheException('Redis配置错误');
        }
    }

    // key value 操作
    public function set($key,$value, $expires = 0){
        $key = $this->appPrefix . $key;

        $value = is_array($value) ? serialize($value) : $value;

        if($expires) {
            $this->redis->setex($key, $expires, $value);
        }else{
            $this->redis->set($key,$value);
        }
    }

    public function get($key){
        $key = $this->appPrefix . $key;
        $value = $this->redis->get($key);

        $jsonData = unserialize($value);
        return (null === $jsonData) ? $value : $jsonData;
    }

    public function del($key){
        $key = $this->appPrefix . $key;
        return $this->redis->del($key);
    }

    // hash操作
    public function hSet($key,$hashKey,$value){
        $key = $this->appPrefix . $key;
        return $this->redis->hSet($key,$hashKey,$value);
    }

    public function hGet($key,$hashKey){
        $key = $this->appPrefix . $key;
        return $this->redis->hGet($key,$hashKey);
    }

    // 队列操作
    public function push($name,$value){
        $name = $this->appPrefix . $name;
        if(!$this->redis->lpush($name,$value)){
            $this->redis->del($name);
            $this->redis->lpush($name,$value);
        }
    }

    public function pop($name){
        $name = $this->appPrefix . $name;
        return $this->redis->rPop($name);
    }

    public function lLen($name){
        $name = $this->appPrefix . $name;
        return $this->redis->lLen($name);
    }

    /**
     * 遍历key
     * @param string $pattern
     * @param int $count
     * @return array
     */
    public function scan($pattern='*',$count=5){
        $it  = NULL;
        $ret = [];
        do
        {
            $keysArr = $this->redis->scan($it, $pattern, $count);
            if ($keysArr)
            {
                foreach ($keysArr as $key)
                {
                    $ret[] = $key;
                }
            }
        } while ($it > 0);
         return $ret;
    }

    /**
     * 遍历redis HASH
     * @param $key
     * @param string $pattern
     * @param int $type
     * @param int $count
     * @return array
     */
    public function hScan($key,$pattern='*',$type=0,$count=50){
        $it  = NULL;
        $ret = [];
        do
        {
            $keysArr = $this->redis->hScan($key,$it,$pattern,$count);
            if ($keysArr)
            {
                foreach ($keysArr as $key=>$value)
                {
                    $type ==0 && $ret[] = $value;
                    $type ==1 && $ret[] = $key;
                    $type ==2 && $ret[$key] = $value;
                }
            }
        } while ($it > 0);
        return $ret;
    }

    /**
     * 遍历redis返回迭代器
     * @param $key
     * @param string $pattern
     * @param int $type
     * @param int $count
     * @return \Generator
     */
    public function hScanYield($key,$pattern='*',$type=0,$count=300){
        $it  = NULL;
        do
        {
            $keysArr = $this->redis->hScan($key,$it,$pattern,$count);
            if ($keysArr)
            {
                foreach ($keysArr as $key=>$value)
                {
                    if($type==0) yield $value;
                    if($type==1) yield $key;
                    if($type==2) yield $key=>$value;
                }
            }
        } while ($it > 0);
    }

    // 单例模式方法
    public function __clone(){}

    static public $instance;//声明一个静态变量（保存在类中唯一的一个实例）

    static public function getInstance(){
        if(!self::$instance) self::$instance = new self();
           return self::$instance;
    }
}